<template>
  <div class="fm-style">
    <a-layout class="fm2-container">
      <a-layout-content class="fm2-main">
        <a-layout>
          <!-- 左边控件 -->
          <a-layout-sider width="250px">
            <div class="components-list">
              <template v-if="basicFields.length">
                <div class="widget-cate">基础字段</div>
                <draggable
                  tag="ul"
                  :list="basicComponents"
                  v-bind="{
                    group: { name: 'people', pull: 'clone', put: false },
                    sort: false,
                    ghostClass: 'ghost'
                  }"
                  @end="handleMoveEnd"
                  @start="handleMoveStart"
                  :move="handleMove"
                >
                  <!-- 基础组件 -->
                  <li class="form-edit-widget-label" :class="{ 'no-put': item.type == 'divider' }" v-for="(item, index) in basicComponents" :key="index">
                    <a v-if="basicFields.indexOf(item.type) >= 0">
                      <i class="icon iconfont" :class="item.icon"></i>
                      <span>{{ item.name }}</span>
                    </a>
                  </li>
                </draggable>
              </template>

              <template v-if="advanceFields.length">
                <div class="widget-cate">高级字段</div>
                <draggable
                  tag="ul"
                  :list="advanceComponents"
                  v-bind="{
                    group: { name: 'people', pull: 'clone', put: false },
                    sort: false,
                    ghostClass: 'ghost'
                  }"
                  @end="handleMoveEnd"
                  @start="handleMoveStart"
                  :move="handleMove"
                >
                  <li class="form-edit-widget-label" :class="{ 'no-put': item.type == 'table' }" v-for="(item, index) in advanceComponents" :key="index">
                    <tamplate v-if="advanceFields.indexOf(item.type) >= 0">
                      <a>
                        <i class="icon iconfont" :class="item.icon"></i>
                        <span>{{ item.name }}</span>
                      </a>
                    </tamplate>
                  </li>
                </draggable>
              </template>

              <template v-if="layoutFields.length">
                <div class="widget-cate">布局字段</div>
                <draggable
                  tag="ul"
                  :list="layoutComponents"
                  v-bind="{
                    group: { name: 'people', pull: 'clone', put: false },
                    sort: false,
                    ghostClass: 'ghost'
                  }"
                  @end="handleMoveEnd"
                  @start="handleMoveStart"
                  :move="handleMove"
                >
                  <li class="form-edit-widget-label no-put" v-for="(item, index) in layoutComponents" :key="index">
                    <!-- <tamplate v-if="advanceFields.indexOf(item.type) >= 0"> -->
                    <a>
                      <i class="icon iconfont" :class="item.icon"></i>
                      <span>{{ item.name }}</span>
                    </a>
                    <!-- </tamplate> -->
                  </li>
                </draggable>
              </template>
            </div>
          </a-layout-sider>
          <!-- 中间面板 -->
          <a-layout class="center-container" direction="vertical">
            <a-layout-header class="btn-bar" style="height: 45px">
              <slot name="action"></slot>
              <a-button v-if="upload" type="link" size="default" icon="upload" @click="handleUpload"> 导入JSON </a-button>
              <a-button v-if="clearable" type="link" size="default" icon="delete" @click="handleClear"> 清空 </a-button>
              <a-button v-if="preview" type="link" size="default" icon="eye" @click="handlePreview"> 预览 </a-button>
              <a-button v-if="generateJson" type="link" size="default" icon="profile" @click="handleGenerateJson"> 生成JSON </a-button>
              <a-button v-if="generateCode" type="link" size="default" icon="file-text" @click="handleGenerateCode"> 生成代码 </a-button>
            </a-layout-header>
            <a-layout-content :class="{ 'widget-empty': widgetForm.list.length == 0 }">
              <widget-form v-if="!resetJson" ref="widgetForm" :data="widgetForm" :select.sync="widgetFormSelect"></widget-form>
            </a-layout-content>
          </a-layout>
          <!-- 右边控件设置面板 -->
          <a-layout-sider class="widget-config-container">
            <a-layout>
              <a-layout-header height="45px">
                <div class="config-tab" :class="{ active: configTab == 'widget' }" @click="handleConfigSelect('widget')">字段属性</div>
                <div class="config-tab" :class="{ active: configTab == 'form' }" @click="handleConfigSelect('form')">表单属性</div>
              </a-layout-header>
              <a-layout-content class="config-content">
                <!-- 控件配置 -->
                <widget-config v-show="configTab == 'widget'" :data="widgetFormSelect"></widget-config>
                <!-- 表单配置 -->
                <form-config v-show="configTab == 'form'" :data="widgetForm.config"></form-config>
              </a-layout-content>
            </a-layout>
          </a-layout-sider>

          <cus-dialog :visible="previewVisible" @on-close="previewVisible = false" ref="widgetPreview" width="1000px" form>
            <generate-form insite="true" @on-change="handleDataChange" v-if="previewVisible" :data="widgetForm" :value="widgetModels" :remote="remoteFuncs" ref="generateForm">
              <template v-slot:blank="scope">
                Width
                <a-input v-model="scope.model.blank.width" style="width: 100px"></a-input>
                Height
                <a-input v-model="scope.model.blank.height" style="width: 100px"></a-input>
              </template>
            </generate-form>

            <template slot="action">
              <a-button type="primary" @click="handleTest"> 获取数据 </a-button>
              <a-button @click="handleReset"> 重置 </a-button>
            </template>
          </cus-dialog>

          <cus-dialog :visible="uploadVisible" @on-close="uploadVisible = false" @on-submit="handleUploadJson" ref="uploadJson" width="800px" form>
            <a-alert type="info" message="JSON格式如下，直接复制生成的json覆盖此处代码点击确定即可"></a-alert>
            <div id="uploadeditor" style="height: 400px; width: 100%">
              {{ jsonEg }}
            </div>
          </cus-dialog>

          <cus-dialog :visible="jsonVisible" @on-close="jsonVisible = false" ref="jsonPreview" width="800px" form>
            <div id="jsoneditor" style="height: 400px; width: 100%">
              {{ jsonTemplate }}
            </div>

            <template slot="action">
              <a-button type="primary" class="json-btn" :data-clipboard-text="jsonCopyValue"> 复制数据 </a-button>
            </template>
          </cus-dialog>

          <cus-dialog :visible="codeVisible" @on-close="codeVisible = false" ref="codePreview" width="800px" form :action="false">
            <a-tabs type="card" style="box-shadow: none" v-model="codeActiveName" @change="codeViewTabChange">
              <a-tab-pane tab="Vue Component" key="vue">
                <div id="vuecodeeditor" style="height: 500px; width: 100%">
                  {{ vueTemplate }}
                </div>
              </a-tab-pane>
              <a-tab-pane tab="HTML" key="html">
                <div id="codeeditor" style="height: 500px; width: 100%">
                  {{ htmlTemplate }}
                </div>
              </a-tab-pane>
            </a-tabs>
          </cus-dialog>
        </a-layout>
      </a-layout-content>
    </a-layout>
  </div>
</template>

<script>
import Draggable from 'vuedraggable'
import WidgetConfig from './WidgetConfig'
import FormConfig from './FormConfig'
import WidgetForm from './WidgetForm'
import CusDialog from './CusDialog'
import GenerateForm from './GenerateForm'
import Clipboard from 'clipboard'
import { basicComponents, layoutComponents, advanceComponents } from './componentsConfig.js'
import request from '../util/request.js'
import generateCode from './generateCode.js'

export default {
  name: 'fm-making-form',
  components: {
    Draggable,
    WidgetConfig,
    FormConfig,
    WidgetForm,
    CusDialog,
    GenerateForm
  },
  props: {
    preview: {
      type: Boolean,
      default: false
    },
    generateCode: {
      type: Boolean,
      default: false
    },
    generateJson: {
      type: Boolean,
      default: false
    },
    upload: {
      type: Boolean,
      default: false
    },
    clearable: {
      type: Boolean,
      default: false
    },
    basicFields: {
      type: Array,
      default: () => ['input', 'textarea', 'number', 'radio', 'checkbox', 'time', 'date', 'rate', 'color', 'select', 'switch', 'slider', 'text', 'treeSelect', 'html']
    },
    advanceFields: {
      type: Array,
      default: () => ['blank', 'imgupload', 'editor', 'cascader']
    },
    layoutFields: {
      type: Array,
      default: () => ['grid', 'divider', 'tabs']
    }
  },
  data() {
    return {
      publicPath: process.env.BASE_URL,
      basicComponents,
      layoutComponents,
      advanceComponents,
      resetJson: false,
      widgetForm: {
        list: [],
        config: {
          labelWidth: 100,
          labelCol: { span: 1, offset: 0 },
          wrapperCol: { span: 1, offset: 0 },
          labelPosition: 'right',
          formLayout: 'vertical',
          size: 'small'
        }
      },
      configTab: 'widget',
      widgetFormSelect: null,
      previewVisible: false,
      jsonVisible: false,
      codeVisible: false,
      uploadVisible: false,
      remoteFuncs: {
        func_test(resolve) {
          setTimeout(() => {
            const options = [
              { id: '1', name: '1111' },
              { id: '2', name: '2222' },
              { id: '3', name: '3333' }
            ]

            resolve(options)
          }, 2000)
        },
        func_treeSelect(resolve) {
          const arr = [
            {
              id: 110000,
              pid: 0,
              name: '北京市',
              level: 1,
              citycode: '010',
              longitude: '116.4073870',
              latitude: '39.9041790',
              is_hot: 0,
              is_delete: 0
            },
            {
              id: 110100,
              pid: 110000,
              name: '北京城区',
              level: 2,
              citycode: '010',
              longitude: '116.4052850',
              latitude: '39.9049890',
              is_hot: 1,
              is_delete: 0
            },
            {
              id: 110101,
              pid: 110100,
              name: '东城区',
              level: 3,
              citycode: '010',
              longitude: '116.4163340',
              latitude: '39.9283590',
              is_hot: 0,
              is_delete: 0
            },
            {
              id: 110102,
              pid: 110100,
              name: '西城区',
              level: 3,
              citycode: '010',
              longitude: '116.3658500',
              latitude: '39.9126000',
              is_hot: 0,
              is_delete: 0
            },
            {
              id: 110105,
              pid: 110100,
              name: '朝阳区',
              level: 3,
              citycode: '010',
              longitude: '116.4431360',
              latitude: '39.9214440',
              is_hot: 0,
              is_delete: 0
            },
            {
              id: 110106,
              pid: 110100,
              name: '丰台区',
              level: 3,
              citycode: '010',
              longitude: '116.2867260',
              latitude: '39.8585380',
              is_hot: 0,
              is_delete: 0
            },
            {
              id: 110107,
              pid: 110100,
              name: '石景山区',
              level: 3,
              citycode: '010',
              longitude: '116.2230150',
              latitude: '39.9063040',
              is_hot: 0,
              is_delete: 0
            },
            {
              id: 110108,
              pid: 110100,
              name: '海淀区',
              level: 3,
              citycode: '010',
              longitude: '116.2977000',
              latitude: '39.9598930',
              is_hot: 0,
              is_delete: 0
            },
            {
              id: 110109,
              pid: 110100,
              name: '门头沟区',
              level: 3,
              citycode: '010',
              longitude: '116.1016680',
              latitude: '39.9408420',
              is_hot: 0,
              is_delete: 0
            },
            {
              id: 110111,
              pid: 110100,
              name: '房山区',
              level: 3,
              citycode: '010',
              longitude: '116.1434260',
              latitude: '39.7488890',
              is_hot: 0,
              is_delete: 0
            },
            {
              id: 110112,
              pid: 110100,
              name: '通州区',
              level: 3,
              citycode: '010',
              longitude: '116.7292300',
              latitude: '39.9164030',
              is_hot: 0,
              is_delete: 0
            },
            {
              id: 110113,
              pid: 110100,
              name: '顺义区',
              level: 3,
              citycode: '010',
              longitude: '116.6614740',
              latitude: '40.1498910',
              is_hot: 0,
              is_delete: 0
            },
            {
              id: 110114,
              pid: 110100,
              name: '昌平区',
              level: 3,
              citycode: '010',
              longitude: '116.2310340',
              latitude: '40.2209520',
              is_hot: 0,
              is_delete: 0
            },
            {
              id: 110115,
              pid: 110100,
              name: '大兴区',
              level: 3,
              citycode: '010',
              longitude: '116.3414830',
              latitude: '39.7269170',
              is_hot: 0,
              is_delete: 0
            },
            {
              id: 110116,
              pid: 110100,
              name: '怀柔区',
              level: 3,
              citycode: '010',
              longitude: '116.6319740',
              latitude: '40.3170030',
              is_hot: 0,
              is_delete: 0
            },
            {
              id: 110117,
              pid: 110100,
              name: '平谷区',
              level: 3,
              citycode: '010',
              longitude: '117.1215890',
              latitude: '40.1408050',
              is_hot: 0,
              is_delete: 0
            },
            {
              id: 110118,
              pid: 110100,
              name: '密云区',
              level: 3,
              citycode: '010',
              longitude: '116.8433510',
              latitude: '40.3770580',
              is_hot: 0,
              is_delete: 0
            },
            {
              id: 110119,
              pid: 110100,
              name: '延庆区',
              level: 3,
              citycode: '010',
              longitude: '115.9746090',
              latitude: '40.4570330',
              is_hot: 0,
              is_delete: 0
            }
          ]
          resolve(arr)
        },
        funcGetToken(resolve) {
          request.get('http://tools-server.xiaoyaoji.cn/api/uptoken').then((res) => {
            resolve(res.uptoken)
          })
        },
        upload_callback(response, file, fileList) {
          console.log('callback', response, file, fileList)
        }
      },
      widgetModels: {},
      blank: '',
      htmlTemplate: '',
      vueTemplate: '',
      jsonTemplate: '',
      uploadEditor: null,
      jsonCopyValue: '',
      jsonClipboard: null,
      jsonEg: `{
        "list": [],
        "config": {
          "labelWidth": 100,
          "labelCol": { "span":1 , "offset": 0},
          "wrapperCol": { "span": 1, "offset": 0 },
          "labelPosition": "right",
          "formLayout": "vertical",
          "size": "small"
        }
      }`,
      codeActiveName: 'vue'
    }
  },
  mounted() {
    this._loadComponents()
  },
  methods: {
    _loadComponents() {
      this.basicComponents = this.basicComponents.map((item) => {
        return {
          ...item
        }
      })
      this.advanceComponents = this.advanceComponents.map((item) => {
        return {
          ...item
        }
      })
      this.layoutComponents = this.layoutComponents.map((item) => {
        return {
          ...item
        }
      })
      console.log(this.layoutComponents)
    },
    handleConfigSelect(value) {
      this.configTab = value
    },
    handleMoveEnd(evt) {
      console.log('end', evt)
    },
    handleMoveStart({ oldIndex }) {
      // console.log('start', oldIndex, this.basicComponents)
    },
    handleMove() {
      return true
    },
    handlePreview() {
      this.previewVisible = true
    },
    handleTest() {
      this.$refs.generateForm.fieldsHidden(['id'], true)
      const that = this
      that.$refs.generateForm
        .getData()
        .then((data) => {
          const h = that.$createElement
          that
            .$info({
              content: h('div', {}, [JSON.stringify(data)]),
              okText: '确认',
              closable: true,
              class: 'date-view',
              onOk() {}
            })
            .catch((e) => {
              console.log(e)
            })
          that.$refs.widgetPreview.end()
        })
        .catch((e) => {
          that.$refs.widgetPreview.end()
        })
    },
    handleReset() {
      this.$refs.generateForm.reset()
    },
    handleGenerateJson() {
      this.jsonVisible = true
      this.jsonTemplate = this.widgetForm
      this.$nextTick(() => {
        const editor = ace.edit('jsoneditor')
        editor.session.setMode('ace/mode/json')

        if (!this.jsonClipboard) {
          this.jsonClipboard = new Clipboard('.json-btn')
          this.jsonClipboard.on('success', (e) => {
            this.$message.success('复制成功')
          })
        }
        this.jsonCopyValue = JSON.stringify(this.widgetForm)
      })
    },
    handleGenerateCode() {
      this.codeVisible = true
      this.htmlTemplate = generateCode(JSON.stringify(this.widgetForm), 'html')
      this.vueTemplate = generateCode(JSON.stringify(this.widgetForm), 'vue')
      this.$nextTick(() => {
        if (this.codeActiveName == 'vue') {
          this.$nextTick(() => {
            const vueeditor = ace.edit('vuecodeeditor')
            vueeditor.session.setMode('ace/mode/html')
          })
        } else if (this.codeActiveName == 'html') {
          this.$nextTick(() => {
            const editor = ace.edit('codeeditor')
            editor.session.setMode('ace/mode/html')
          })
        }
      })
    },
    codeViewTabChange(e) {
      // 生成代码弹框选项卡切换监听
      if (e == 'vue') {
        this.$nextTick(() => {
          const vueeditor = ace.edit('vuecodeeditor')
          vueeditor.session.setMode('ace/mode/html')
        })
      } else if (e == 'html') {
        this.$nextTick(() => {
          const editor = ace.edit('codeeditor')
          editor.session.setMode('ace/mode/html')
        })
      }
    },
    handleUpload() {
      this.uploadVisible = true
      this.$nextTick(() => {
        this.uploadEditor = ace.edit('uploadeditor')
        this.uploadEditor.session.setMode('ace/mode/json')
      })
    },
    handleUploadJson() {
      try {
        this.setJSON(JSON.parse(this.uploadEditor.getValue()))
        this.uploadVisible = false
      } catch (e) {
        this.$message.error(e.message)
        this.$refs.uploadJson.end()
      }
    },
    handleClear() {
      this.widgetForm = {
        list: [],
        config: {
          labelWidth: 100,
          labelCol: { span: 1, offset: 0 },
          wrapperCol: { span: 1, offset: 0 },
          labelPosition: 'right',
          formLayout: 'vertical',
          size: 'small'
        }
      }

      this.widgetFormSelect = {}
    },
    clear() {
      this.handleClear()
    },
    getJSON() {
      return this.widgetForm
    },
    getHtml() {
      return generateCode(JSON.stringify(this.widgetForm))
    },
    setJSON(json) {
      this.widgetForm = json
      if (json.list.length > 0) {
        this.widgetFormSelect = json.list[0]
      }
    },
    handleInput(val) {
      console.log(val)
      this.blank = val
    },
    handleDataChange(field, value, data) {
      console.log(field, value, data)
    }
  },
  watch: {
    widgetForm: {
      deep: true,
      handler: function (val) {
        console.log(this.$refs.widgetForm)
      }
    }
    // $lang: function (val) {
    //   this._loadComponents()
    // }
  }
}
</script>
